package com.zn.znch.yhp.znchv2.service;


import com.zn.znch.yhp.znchv2.common.PointDate;
import com.zn.znch.yhp.znchv2.domain.DTO.CCPointData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;
import org.apache.commons.math3.stat.regression.SimpleRegression;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class CCModelUpdate {

    public static String path = "D:/temp/znch/cc/data";
    public static String configPath = "D:/temp/znch/cc/config/config.properties";

    public static void main(String[] args) {
        CCModelUpdateTask();
    }

    @Scheduled(cron= "0 30 0 * * ?")
    public static void CCModelUpdateTask() {
        log.info("长吹模型更新任务开始");
        //加载目录下所有的数据文件
        try {
            File directory = new File(path);
            String[] FileList = directory.list();
            Map<String,String> map = new HashMap<>();
            for (int i = 0; i < FileList.length; i++) {
                String filePath = directory.getAbsolutePath()+"/"+FileList[i];
                String key = FileList[i];
                HashMap<String,String> data = getParameters(filePath,key);
                String params = data.get("params");
                map.put(key,params);
            }
            Properties properties = new Properties();
            FileInputStream fis = new FileInputStream(configPath);
            properties.load(fis);
            for (String key:map.keySet()) {
                // 设置属性值
                properties.setProperty(key, map.get(key));
            }
            FileOutputStream fos = new FileOutputStream(configPath);
            properties.store(fos, "Generated configuration properties file");
            fos.close();
        } catch (Exception e) {
            log.error("配置文件更新失败，Exception{}",e);
        }
        log.info("长吹模型更新任务完成");
    }

    private static HashMap<String,String> getParameters(String Filepath, String fileName) throws IOException {
        File file = new File(Filepath);
        FileReader fr = new FileReader(file);
        BufferedReader br = new BufferedReader(fr);
        String line = br.readLine();
        List<CCPointData> pointDatas = new ArrayList<>();
        int count = 0;
        while (line != null) {
            String[] lineStr = line.split(",");
            if(Double.parseDouble(lineStr[1])>400){
                count++;
            }
            CCPointData pointData = new CCPointData(lineStr[0],Double.parseDouble(lineStr[1]),
                    Double.parseDouble(lineStr[2]),Double.valueOf(lineStr[3]),lineStr[4]);
            pointDatas.add(pointData);
            line = br.readLine();
        }
        if (count<=30000){
            log.info("当前文件{}有效数据不满足30000，暂停更新模型参数",fileName);
            return new HashMap<>();
        }

        HashMap<String,String> result = null;
        //先根据烟气温降偏差左拟合，R2<0.9则使用蒸汽焓增，如果是屏过、末过，直接使用蒸汽焓增
        //type=1则是烟气温降拟合，type=2则是蒸汽焓增*fuhe拟合
        fileName = fileName.replace(".csv","");
        if(!PointDate.wenjiangPoint.keySet().contains(fileName)){
            result = quadraticFitting2(pointDatas,2);
            System.out.println(fileName+" type : 2 , rSquared "+result.get("rSquared"));
        }else{
            result = quadraticFitting(pointDatas,1);
            System.out.println(fileName+" type : 1 , rSquared "+result.get("rSquared"));
            Double rSquared = Double.parseDouble(result.get("rSquared"));
            if(rSquared<0.9){
                result = quadraticFitting(pointDatas,2);
                System.out.println(fileName+" type : 2 , rSquared "+result.get("rSquared"));
                rSquared = Double.parseDouble(result.get("rSquared"));
            }
        }
        return result;

    }

    private static HashMap<String, String> quadraticFitting2(List<CCPointData> pointDatas,Integer type) {
        //按照负荷从大到小排序
        Collections.sort(pointDatas, new Comparator<CCPointData>() {
            @Override
            public int compare(CCPointData o1, CCPointData o2) {
                return Double.compare(o2.getFuhe(), o1.getFuhe());
            }
        });
        //按负荷对数据进行切片,切片后按不同列降序
        List<CCPointData> xunlianData = new ArrayList();
        for (int i = 0; i < pointDatas.size()-1; ) {
            List<CCPointData> list = new ArrayList<>();
            CCPointData start = pointDatas.get(i);
            list.add(start);
            i++;
            CCPointData next = pointDatas.get(i);
            while ((start.getFuhe()-next.getFuhe()<=5) && i < pointDatas.size()-1){
                list.add(next);
                i++;
                next = pointDatas.get(i);
            }
            int begin = new Double(list.size()*0.25).intValue();
            int end = new Double(list.size()*0.75).intValue()+1;
            list = list.subList(begin,end);
            double  pingjun = list.stream().mapToDouble(CCPointData::getFuhe).average().orElse(0);
            List result = list.stream().filter(data->data.getFuhe()>=pingjun).collect(Collectors.toList());
            xunlianData.addAll(result);
        }
        double[] xData = new double[xunlianData.size()];
        double[] yData = new double[xunlianData.size()];
        for (int i = 0; i < xunlianData.size(); i++) {
            xData[i] = xunlianData.get(i).getFuhe();
            yData[i] = xunlianData.get(i).getZqhz();
        }
        WeightedObservedPoints points = new WeightedObservedPoints();
        for (int i = 0; i < xData.length; i++) {
            points.add(xData[i], yData[i]);
        }
        // 进行一元二次拟合
        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(2);
        double[] params = fitter.fit(points.toList());
        SimpleRegression regression = new SimpleRegression();
        for (int i = 0; i < xData.length; i++) {
            regression.addData(xData[i], yData[i]);
        }
        double rSquared = regression.getRSquare();

        HashMap<String,String> result = new HashMap<>();
        result.put("rSquared",rSquared+"");
        StringBuffer sb =new StringBuffer();
        sb.append(params[2]).append(",").append(params[1]).append(",").append(params[0]).append(",")
                .append(type.intValue()).append(",").append(rSquared);
        result.put("params",sb.toString());
        return result;
    }


    //筛选数据，并计算一元二次系数
    //type=1则是烟气温降拟合，type=2则是蒸汽焓增*fuhe拟合
    public static HashMap<String,String>




    quadraticFitting(List<CCPointData> pointDatas,Integer type){
        //按照负荷从小到大排序
        Collections.sort(pointDatas, new Comparator<CCPointData>() {
            @Override
            public int compare(CCPointData o1, CCPointData o2) {
                return Double.compare(o1.getFuhe(), o2.getFuhe());
            }
        });
        //CCPointData,切片后按不同列降序
        List<List<CCPointData>> xunlianData = new ArrayList();
        for (int i = 0; i < pointDatas.size()-1; ) {
            List<CCPointData> list = new ArrayList<>();
            CCPointData start = pointDatas.get(i);
            list.add(start);
            CCPointData next = pointDatas.get(i+1);
            i++;
            while ((next.getFuhe() - start.getFuhe()<=5) && i < pointDatas.size()-1){
                list.add(next);
                i++;
                next = pointDatas.get(i);
            }

            xunlianData.add(list);
        }

        List<CCPointData> saixuanList = new ArrayList<>();
        for (int i = 0; i < xunlianData.size(); i++) {
            List<CCPointData> list= xunlianData.get(i);
            //按从大到小排序
            if(type == 1){
                Collections.sort(list, new Comparator<CCPointData>() {
                    @Override
                    public int compare(CCPointData o1, CCPointData o2) {
                        return Double.compare(o2.getYqwj(),o1.getYqwj());
                    }
                });
            }else{
                Collections.sort(list, new Comparator<CCPointData>() {
                    @Override
                    public int compare(CCPointData o1, CCPointData o2) {
                        return Double.compare(o2.getZqhz(),o1.getZqhz());
                    }
                });
            }

            //获取前95%，不足+1
            int count = new Double(list.size()*0.95).intValue() +1;
            list = list.subList(0,count);
            saixuanList.addAll(list);
        }

        double[] xData = new double[saixuanList.size()];
        double[] yData1 = new double[saixuanList.size()];
        double[] yData2 = new double[saixuanList.size()];
        for (int i = 0; i < saixuanList.size(); i++) {
            xData[i] = saixuanList.get(i).getFuhe();
            yData1[i] = saixuanList.get(i).getYqwj();
            yData2[i] = saixuanList.get(i).getZqhz()*saixuanList.get(i).getFuhe();
        }
        double[] yData = new double[saixuanList.size()];
        if(type == 1){
            yData = yData1;
        }else {
            yData = yData2;
        }

        WeightedObservedPoints points = new WeightedObservedPoints();
        for (int i = 0; i < xData.length; i++) {
            points.add(xData[i], yData[i]);
        }

        // 进行一元二次拟合
        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(2);
        double[] params = fitter.fit(points.toList());
        double[] yDataYuche = new double[saixuanList.size()];
        for (int i = 0; i < xData.length; i++) {
            double x = xData[i];
            double y = x*x*params[2]+x*params[1]+params[0];
            yDataYuche[i] = y;
        }

        SimpleRegression regression = new SimpleRegression();
        for (int i = 0; i < xData.length; i++) {
            regression.addData(yDataYuche[i], yData[i]);
        }
        double rSquared = regression.getRSquare();
        HashMap<String,String> result = new HashMap<>();
        result.put("rSquared",rSquared+"");
        StringBuffer sb =new StringBuffer();
        sb.append(params[2]).append(",").append(params[1]).append(",").append(params[0]).append(",")
                .append(type.intValue()).append(",").append(rSquared);
        result.put("params",sb.toString());
        return result;
    }
}
